package com.ai.bitcoin.schedule.task;

import com.ai.bitcoin.bean.BccAllInfo;
import com.ai.bitcoin.constant.Bcc;
import com.ai.bitcoin.jpa.entity.*;
import com.ai.bitcoin.jpa.service.*;
import com.ai.bitcoin.redis.service.BccRedisService;
import com.ai.bitcoin.redis.service.RedisLockService;
import com.ai.bitcoin.serialize.BeanSerial;
import com.ai.bitcoin.thread.pool.TaskExecutor;
import com.ai.bitcoin.utils.MathUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 产生cache: rank
 *
 * @author Jason
 * @date 2018/3/29
 **/
@Slf4j
@Component
public class RankTask extends AbstractTask {
    @Autowired
    BccScoreRuleService bccScoreRuleService;
    @Autowired
    BccBasicInfoService bccBasicInfoService;
    @Autowired
    BccRedisService bccRedisService;
    @Autowired
    BccTradeService bccTradeService;
    @Autowired
    BccRankService bccRankService;
    @Autowired
    BccBatchService bccBatchService;
    @Autowired
    BccRankHisService BccRankHisService;
    @Autowired
    BccBasicInfoCrawlService bccBasicInfoCrawlService;
    @Autowired
    BccInfoEditService bccInfoEditService;
    @Autowired
    BccDailyInfoService bccDailyInfoService;
    @Autowired
    BccDailyInfoHisService bccDailyInfoHisService;
    @Autowired
    RedisLockService redisLockService;
    @Autowired
    TaskExecutor taskExecutor;
    @Autowired
    BccShowControlService bccShowControlService;
    @Autowired
    BccPriceInfoService bccPriceInfoService;
    @Autowired
    BccIndexInfoService bccIndexInfoService;
    @Autowired
    BccPriceDayService bccPriceDayService;

    public String uuid;

    @Override
    public void execute() {
        System.currentTimeMillis();
        long start;
        List<BccBatch> priceInfoBatchList = bccBatchService.findByBatchTypeAndBatchStateOrderByBatchTimeEndDesc(Bcc.BathType.UPDATE_DAILY_INFO, Bcc.BathState.UPDATE_DONE);
        if (priceInfoBatchList.size() == 0) {
            log.info("没有要处理的新信息，不需要重新计算");
            return;
        }
        List<BccBasicInfo> btcInfoList = bccBasicInfoService.findByBccIdAndRecordState(getBtcId(), Bcc.RecordState.PUBLISH);
        if (btcInfoList.size() == 0) {
            log.info("没有找到base比特币信息:{}", getBtcId());
            return;
        }

        BccBatch latestBasicInfoBatch = priceInfoBatchList.get(0);
        List<BccBasicInfo> basicInfoList = bccBasicInfoService.findByRecordState(Bcc.RecordState.PUBLISH);
        if (basicInfoList.size() == 0) {
            log.info("该批次爬取的数据为空");
            return;
        }
        String latestBasicInfoBathNo = latestBasicInfoBatch.getBatchNo();

        log.info("数据条数：{}", basicInfoList.size());
        if (btcInfoList.size() > 1) {
            log.info("base比特币信息有误，edits:{}", JSONArray.fromObject(btcInfoList).toString());
            return;
        }
        BccBasicInfo btcBasicInfo = btcInfoList.get(0);
        if (priceInfoBatchList.size() > 1) {
            log.info("任务好慢，错过了{}个版本了,把这些版本更新状态为:{}", priceInfoBatchList.size() - 1, Bcc.BathState.EXPIRE);
            for (int i = 1; i < priceInfoBatchList.size(); i++) {
                BccBatch bccBatch = priceInfoBatchList.get(i);
                bccBatch.setBatchState(Bcc.BathState.EXPIRE);
                bccBatchService.save(bccBatch);
                log.info("batchNo:{}", BeanSerial.Bean2Json(bccBatch));
            }
        }

        log.info("清理未发布的脏数据");
        bccRankService.deleteNoPublish();

        log.info("开始处理，batchNo:{}", BeanSerial.Bean2Json(btcBasicInfo).toString());

        log.info("获取元数据");
        start = System.currentTimeMillis();
        List<BccAllInfo> allInfos = new ArrayList<>();
        BccBasicInfo basicInfo;
        for (int i = 0; i < basicInfoList.size(); i++) {
            basicInfo = basicInfoList.get(i);
            String bccId = basicInfo.getBccId();
            log.info("{}:{}", i, bccId);
            BccAllInfo itemAllInfo = getAllInfo(basicInfo);
            allInfos.add(itemAllInfo);
        }

        log.info("开始计算方差");
        Map<String, Double> normal = normal(basicInfoList);

        log.info("开始计算各维度评分");
        BccScoreRule bccScoreRule;
        for (int i = 0; i < allInfos.size(); i++) {
            BccAllInfo bccAllInfo = allInfos.get(i);
            basicInfo = bccAllInfo.getBccBasicInfo();
            String bccId = basicInfo.getBccId();
            JSONObject itemField = new JSONObject();
            log.info("计算评分，i:{} bccId:{}", i, basicInfo.getBccId());
            BccRank bccRank = bccRankService.findByBccIdAndRecordState(bccId, Bcc.RecordState.UN_PUBLISH);
            if (null == bccRank) {
                bccRank = getInitBccRank(latestBasicInfoBathNo, bccId);
            }

            //基础评分
            List<BccScoreRule> ruleList = getBitCoinHandleRule(basicInfo, Bcc.HandleRule.ScoreClass.SCORE);
            if (ruleList != null) {
                for (BccScoreRule aRuleList : ruleList) {
                    bccScoreRule = aRuleList;
                    float score = calculateBasicScore3(normal, bccAllInfo, bccScoreRule, itemField);
                    setScore(bccRank, bccScoreRule.getScoreType(), score);
                }
            }

            //设置综合评分
            ruleList = getBitCoinHandleRule(basicInfo, Bcc.HandleRule.ScoreClass.RANK);
            if (ruleList != null) {
                for (BccScoreRule aRuleList : ruleList) {
                    bccScoreRule = aRuleList;
                    calculateAndSetRankScore(bccRank, bccScoreRule);
                }
            }

            bccRankService.save(bccRank);

            saveEditField(basicInfo, itemField);
        }

        log.info("开始计算各维度评分，consume:{}ms", (System.currentTimeMillis() - start));

        log.info("设置rank_supply_score");
        List<BccRank> unPublishRanks = bccRankService.findByBatchNoAndRecordStateOrderBySupplyScoreDesc(latestBasicInfoBathNo, Bcc.RecordState.UN_PUBLISH);
        setScoreRank(unPublishRanks, Bcc.RankType.RANK_SUPPLY_SCORE);

        log.info("设置rank_need_score");
        unPublishRanks = bccRankService.findByBatchNoAndRecordStateOrderByNeedScoreDesc(latestBasicInfoBathNo, Bcc.RecordState.UN_PUBLISH);
        setScoreRank(unPublishRanks, Bcc.RankType.RANK_NEED_SCORE);

        log.info("设置RANK_INNER_SCORE");
        unPublishRanks = bccRankService.findByBatchNoAndRecordStateOrderByInnerScoreDesc(latestBasicInfoBathNo, Bcc.RecordState.UN_PUBLISH);
        setScoreRank(unPublishRanks, Bcc.RankType.RANK_INNER_SCORE);

        log.info("设置RANK_SCORE_SCORE");
        unPublishRanks = bccRankService.findByBatchNoAndRecordStateOrderByMoodScoreDesc(latestBasicInfoBathNo, Bcc.RecordState.UN_PUBLISH);
        setScoreRank(unPublishRanks, Bcc.RankType.RANK_MOOD_SCORE);

        log.info("设置RANK_SFAE_SCORE");
        unPublishRanks = bccRankService.findByBatchNoAndRecordStateOrderBySafeScoreDesc(latestBasicInfoBathNo, Bcc.RecordState.UN_PUBLISH);
        setScoreRank(unPublishRanks, Bcc.RankType.RANK_SFAE_SCORE);

        log.info("设置RANK_FUTURE_SCORE");
        unPublishRanks = bccRankService.findByBatchNoAndRecordStateOrderByFutureScoreDesc(latestBasicInfoBathNo, Bcc.RecordState.UN_PUBLISH);
        setScoreRank(unPublishRanks, Bcc.RankType.RANK_FUTURE_SCORE);

        log.info("设置value");
        unPublishRanks = bccRankService.findByBatchNoAndRecordStateOrderByValueScoreDesc(latestBasicInfoBathNo, Bcc.RecordState.UN_PUBLISH);
        setRank(unPublishRanks, Bcc.RankType.RANK_VALUE_TODAY);

        log.info("设置potential");
        unPublishRanks = bccRankService.findByBatchNoAndRecordStateOrderByPotentialScoreDesc(latestBasicInfoBathNo, Bcc.RecordState.UN_PUBLISH);
        setRank(unPublishRanks, Bcc.RankType.RANK_POTENTIAL_TODAY);

        log.info("设置gas");
        unPublishRanks = bccRankService.findByBatchNoAndRecordStateOrderByGasScoreAsc(latestBasicInfoBathNo, Bcc.RecordState.UN_PUBLISH);
        setRank(unPublishRanks, Bcc.RankType.RANK_GAS_TODAY);

        log.info("设置RankUp");
        List<BccRank> bccRanks = setRankUp(latestBasicInfoBathNo);

        setYesterday(bccRanks);

        log.info("save to rank_his");
        List<BccRank> publishRanks = bccRankService.findByRecordState(Bcc.RecordState.PUBLISH);
        for (BccRank publishRank : publishRanks) {
            log.info("bccId:{}", publishRank.getBccId());
            save2RankHis(publishRank);
        }

        log.info("换版bcc_rank,batchNo:{}", latestBasicInfoBatch.getBatchNo());
        bccRankService.updateRank(latestBasicInfoBathNo);

        log.info("刷新到redis");
        cache2Redis();

        latestBasicInfoBatch.setBatchTimeEnd(new Date());
        latestBasicInfoBatch.setBatchState(Bcc.BathState.HANDLE_DONE);
        bccBatchService.save(latestBasicInfoBatch);
    }

    private void setYesterday(List<BccRank> unPublishRanks) {
        int count = unPublishRanks.size();

        for (BccRank bccRank : unPublishRanks) {
            bccRank.setValueScoreDefeat(((float) (count - bccRank.getRankValueToday() - 1) / count));

            BccRank rankYesterday = bccRankService.findByBccIdAndRecordState(bccRank.getBccId(), Bcc.RecordState.PUBLISH);
            if (rankYesterday != null) {
                //昨日价值排名
                bccRank.setRankValueYesterday(rankYesterday.getRankValueToday());

                //昨日价值评分
                bccRank.setValueScoreYesterday(rankYesterday.getValueScore());
                bccRank.setValueScoreChange(getChange(bccRank.getValueScoreYesterday(), bccRank.getValueScore()));
                //昨日价值评分击败率
                bccRank.setValueScoreDefeatYesterday(rankYesterday.getValueScoreDefeat());
                bccRank.setValueScoreDefeatChange(getChange(bccRank.getValueScoreDefeatYesterday(), bccRank.getValueScoreDefeat()));

                //昨日需求评分
                bccRank.setNeedScoreYesterday(rankYesterday.getNeedScore());
                bccRank.setNeedScoreChange(getChange(bccRank.getNeedScoreYesterday(), bccRank.getNeedScore()));
                //昨日心情评分
                bccRank.setMoodScoreYesterday(rankYesterday.getMoodScore());
                bccRank.setMoodScoreChange(getChange(bccRank.getMoodScoreYesterday(), bccRank.getMoodScore()));
                //安全
                bccRank.setSafeScoreYesterday(rankYesterday.getSafeScore());
                bccRank.setSafeScoreChange(getChange(bccRank.getSafeScoreYesterday(), bccRank.getSafeScore()));
                //供应
                bccRank.setSupplyScoreYesterday(rankYesterday.getSupplyScore());
                bccRank.setSupplyScoreChange(getChange(bccRank.getSupplyScoreYesterday(), bccRank.getSupplyScore()));
                //未来
                bccRank.setSupplyScoreYesterday(rankYesterday.getSupplyScore());
                bccRank.setSupplyScoreChange(getChange(bccRank.getSupplyScoreYesterday(), bccRank.getSupplyScore()));
                //inner
                bccRank.setInnerScoreYesterday(rankYesterday.getInnerScore());
                bccRank.setInnerScoreChange(getChange(bccRank.getInnerScoreYesterday(), bccRank.getInnerScore()));

            }

            //量化价格
            String price = bccRedisService.getCurrentPrice(bccRank.getBccId());
            if (StringUtils.isNotEmpty(price)) {
                bccRank.setValuePriceUsd(getFloat(JSONObject.fromObject(price).optString("priceUsd")));
                bccRank.setValuePriceCny(getFloat(JSONObject.fromObject(price).optString("priceCny")));
                bccRank.setValuePriceBtc(getFloat(JSONObject.fromObject(price).optString("priceBtc")));
            }
            bccRankService.save(bccRank);
        }

    }

    private float getChange(float yesterday, float today) {
        if (yesterday == 0)
            return 0;
        return today - yesterday;

    }

    private Map normal(List<BccBasicInfo> basicInfoList) {
        log.info("开始计算方差、mean");
        Map<String, Double> jsonObject = new HashMap<>();
        //totalSupply
        List<Double> totalSupply = new ArrayList<>();
        List<Double> availableSupply = new ArrayList<>();
        List<Double> icoToNowDay = new ArrayList<>();
        List<Double> onlineToNowDay = new ArrayList<>();
        List<Double> officialSiteUrlCount = new ArrayList<>();
        List<Double> volumeUsdAver30 = new ArrayList<>();//volumeUsd 30日平均
        BccBasicInfo bccBasicInfo;
        for (BccBasicInfo aBasicInfoList : basicInfoList) {
            bccBasicInfo = aBasicInfoList;
            String bccId = bccBasicInfo.getBccId();
            totalSupply.add(getDouble(bccBasicInfo.getTotalSupply()));
            availableSupply.add(getDouble(bccBasicInfo.getAvailableSupply()));
            icoToNowDay.add(getDouble(bccBasicInfo.getIcoToNowDay()));
            onlineToNowDay.add(getDouble(bccBasicInfo.getOnlineToNowDay()));
            officialSiteUrlCount.add(StringUtils.isNotEmpty(bccBasicInfo.getOfficialSiteUrl()) ? 1d : 0d);
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.add(Calendar.DAY_OF_MONTH, -30);

            List<BccPriceDay> priceDays = bccPriceDayService.findByBccIdAndCreateTimeGreaterThan(bccId, calendar.getTime());
            BccPriceDay priceDay;
            List<Double> volumeList = new ArrayList<>();
            for (BccPriceDay priceDay1 : priceDays) {
                priceDay = priceDay1;
                Double volume = getDouble(priceDay.getVolumeBtc());
                volumeList.add(volume);
            }
            volumeUsdAver30.add(MathUtil.mean(convert(volumeList)));
        }
        jsonObject.put(getMeanName(Bcc.Item.volumeUsdAver30), MathUtil.mean(convert(volumeUsdAver30)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.volumeUsdAver30), MathUtil.standardDeviation(convert(volumeUsdAver30)));
        jsonObject.put(getMeanName(Bcc.Item.totalSupply), MathUtil.mean(convert(totalSupply)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.totalSupply), MathUtil.standardDeviation(convert(totalSupply)));
        jsonObject.put(getMeanName(Bcc.Item.availableSupply), MathUtil.mean(convert(availableSupply)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.availableSupply), MathUtil.standardDeviation(convert(availableSupply)));
        jsonObject.put(getMeanName(Bcc.Item.icoToNowDay), MathUtil.mean(convert(icoToNowDay)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.icoToNowDay), MathUtil.standardDeviation(convert(icoToNowDay)));
        jsonObject.put(getMeanName(Bcc.Item.onlineToNowDay), MathUtil.mean(convert(onlineToNowDay)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.onlineToNowDay), MathUtil.standardDeviation(convert(onlineToNowDay)));
        jsonObject.put(getMeanName(Bcc.Item.officialSiteUrlCount), MathUtil.mean(convert(officialSiteUrlCount)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.officialSiteUrlCount), MathUtil.standardDeviation(convert(officialSiteUrlCount)));

        List<BccDailyInfo> dailyInfos = bccDailyInfoService.findByRecordState(Bcc.RecordState.PUBLISH);
        List<Double> top3Ratio = new ArrayList<>();
        List<Double> marketCount = new ArrayList<>();
        List<Double> blockReward = new ArrayList<>();
        List<Double> computeAbility = new ArrayList<>();
        List<Double> githubStarCount = new ArrayList<>();
        List<Double> blockCreateTimeGap = new ArrayList<>();
        List<Double> dailyVisitRank = new ArrayList<>();
        List<Double> dailyVisitRank1dChange = new ArrayList<>();
        List<Double> snsCommentCount = new ArrayList<>();
        List<Double> searchIndex = new ArrayList<>();
        BccDailyInfo bccDailyInfo;
        for (BccDailyInfo dailyInfo : dailyInfos) {
            bccDailyInfo = dailyInfo;
            String bccId = bccDailyInfo.getBccId();
            top3Ratio.add(getDouble(bccDailyInfo.getTop3Ratio()));
            marketCount.add(getDouble(bccDailyInfo.getMarketCount()));
            blockReward.add(getDouble(bccDailyInfo.getBlockReward()));
            computeAbility.add(getDouble(bccDailyInfo.getComputeAbility()));
            githubStarCount.add(getDouble(bccDailyInfo.getMarketCount()));
            blockCreateTimeGap.add(getDouble(bccDailyInfo.getBlockCreateTimeGap()));
            dailyVisitRank.add(getDouble(bccDailyInfo.getDailyVisitRank()));

            List<BccDailyInfoHis> dailyInfoHisList = bccDailyInfoHisService.findByBccIdYesterday(bccId);
            if (dailyInfoHisList.size() > 0) {
                BccDailyInfoHis yesterday = dailyInfoHisList.get(0);
                dailyVisitRank1dChange.add(getChangeRate(getDouble(bccDailyInfo.getDailyVisitRank()), getDouble(yesterday.getDailyVisitRank())));
                snsCommentCount.add(getChangeRate(getDouble(bccDailyInfo.getSnsCommentCount()), getDouble(yesterday.getSnsCommentCount())));
                searchIndex.add(getChangeRate(getDouble(bccDailyInfo.getSearchIndex()), getDouble(yesterday.getSearchIndex())));
            }
        }
        jsonObject.put(getMeanName(Bcc.Item.top3Ratio), MathUtil.mean(convert(top3Ratio)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.top3Ratio), MathUtil.standardDeviation(convert(top3Ratio)));
        jsonObject.put(getMeanName(Bcc.Item.marketCount), MathUtil.mean(convert(marketCount)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.marketCount), MathUtil.standardDeviation(convert(marketCount)));
        jsonObject.put(getMeanName(Bcc.Item.blockReward), MathUtil.mean(convert(blockReward)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.blockReward), MathUtil.standardDeviation(convert(blockReward)));
        jsonObject.put(getMeanName(Bcc.Item.computeAbility), MathUtil.mean(convert(computeAbility)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.computeAbility), MathUtil.standardDeviation(convert(computeAbility)));
        jsonObject.put(getMeanName(Bcc.Item.githubStarCount), MathUtil.mean(convert(githubStarCount)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.githubStarCount), MathUtil.standardDeviation(convert(githubStarCount)));
        jsonObject.put(getMeanName(Bcc.Item.blockCreateTimeGap), MathUtil.mean(convert(blockCreateTimeGap)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.blockCreateTimeGap), MathUtil.standardDeviation(convert(blockCreateTimeGap)));
        jsonObject.put(getMeanName(Bcc.Item.dailyVisitRank), MathUtil.mean(convert(dailyVisitRank)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.dailyVisitRank), MathUtil.standardDeviation(convert(dailyVisitRank)));
        jsonObject.put(getMeanName(Bcc.Item.dailyVisitRank1dChange), MathUtil.mean(convert(dailyVisitRank1dChange)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.dailyVisitRank1dChange), MathUtil.standardDeviation(convert(dailyVisitRank1dChange)));
        jsonObject.put(getMeanName(Bcc.Item.snsCommentCount), MathUtil.mean(convert(snsCommentCount)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.snsCommentCount), MathUtil.standardDeviation(convert(snsCommentCount)));
        jsonObject.put(getMeanName(Bcc.Item.searchIndex), MathUtil.mean(convert(searchIndex)));
        jsonObject.put(getStandardDeviationName(Bcc.Item.searchIndex), MathUtil.standardDeviation(convert(searchIndex)));

        BccBatch bccBatch = bccBatchService.findOneByBatchTypeAndBatchStateOrderByBatchTimeEndDesc(Bcc.BathType.CRAWL_PRICE_INFO, Bcc.BathState.HANDLE_DONE);
        if (bccBatch != null && StringUtils.isNotEmpty(bccBatch.getBatchNo())) {
            List<BccPriceInfo> priceInfos = bccPriceInfoService.findByBatchNo(bccBatch.getBatchNo());
            List<Double> volumeUsd = new ArrayList<>();
            BccPriceInfo bccPriceInfo;
            for (BccPriceInfo priceInfo : priceInfos) {
                bccPriceInfo = priceInfo;
                volumeUsd.add(getDouble(bccPriceInfo.getVolumeUsd()));
            }
            jsonObject.put(getMeanName(Bcc.Item.volumeUsd), MathUtil.mean(convert(volumeUsd)));
            jsonObject.put(getStandardDeviationName(Bcc.Item.volumeUsd), MathUtil.standardDeviation(convert(volumeUsd)));
        }
        bccBatch = bccBatchService.findOneByBatchTypeAndBatchStateOrderByBatchTimeEndDesc(Bcc.BathType.CRAWL_INDEX_INFO, Bcc.BathState.HANDLE_DONE);
        if (bccBatch != null && StringUtils.isNotEmpty(bccBatch.getBatchNo())) {
            String batchNo = bccBatch.getBatchNo();
            String key = Bcc.Item.whole_average_daily_30d;
            List<BccIndexInfo> indexInfos = bccIndexInfoService.findByBatchNoAndIndexTitle(batchNo, key);
            List<Double> whole_average_daily_30d = new ArrayList<>();
            BccIndexInfo bccIndexInfo;
            for (BccIndexInfo indexInfo : indexInfos) {
                bccIndexInfo = indexInfo;
                whole_average_daily_30d.add(getDouble(bccIndexInfo.getIndexValue()));
            }
            jsonObject.put(getMeanName(Bcc.Item.whole_average_daily_30d), MathUtil.mean(convert(whole_average_daily_30d)));
            jsonObject.put(getStandardDeviationName(Bcc.Item.whole_average_daily_30d), MathUtil.standardDeviation(convert(whole_average_daily_30d)));
        }

        return jsonObject;
    }

    private double getChangeRate(double today, double yesterday) {
        if (yesterday == 0)
            return 0;
        else
            return (today - yesterday) / yesterday;

    }

    private double[] convert(List<Double> list) {
        double[] doubles = new double[list.size()];
        for (int i = 0; i < list.size(); i++) {
            doubles[i] = list.get(i);
        }
        return doubles;
    }

    private String getMeanName(String name) {
        return name + "_mean";
    }

    private String getStandardDeviationName(String name) {
        return name + "_standardDeviation";
    }

    private List<BccRank> setRankUp(String latestBatch) {
        List<BccRank> unPublishRanks;
        unPublishRanks = bccRankService.findByBatchNoAndRecordState(latestBatch, Bcc.RecordState.UN_PUBLISH);
        BccRank bccRank;
        for (BccRank unPublishRank : unPublishRanks) {
            bccRank = unPublishRank;
            int valueUp = getRankUp(bccRank.getRankValueYesterday(), bccRank.getRankValueToday());
            bccRank.setValueUp(valueUp);
            bccRank.setValueUpPercent(getRankUpPercent(valueUp, bccRank.getRankValueYesterday()));

            int potentialUp = getRankUp(bccRank.getRankPotentialYesterday(), bccRank.getRankPotentialToday());
            bccRank.setPotentialUp(potentialUp);
            bccRank.setPotentialUpPercent(getRankUpPercent(potentialUp, bccRank.getRankPotentialYesterday()));

            int gasUp = getRankUp(bccRank.getRankGasYesterday(), bccRank.getRankGasToday());
            bccRank.setGasUp(gasUp);

            bccRankService.save(bccRank);
        }
        unPublishRanks = bccRankService.findByBatchNoAndRecordStateOrderByValueUpPercentDesc(latestBatch, Bcc.RecordState.UN_PUBLISH);
        for (int i = 0; i < unPublishRanks.size(); i++) {
            bccRank = unPublishRanks.get(i);
            bccRank.setRankValueUp((i + 1));
            bccRankService.save(bccRank);
        }
        unPublishRanks = bccRankService.findByBatchNoAndRecordStateOrderByPotentialUpPercentDesc(latestBatch, Bcc.RecordState.UN_PUBLISH);
        for (int i = 0; i < unPublishRanks.size(); i++) {
            bccRank = unPublishRanks.get(i);
            bccRank.setRankPotentialUp((i + 1));
            bccRankService.save(bccRank);
        }
        return unPublishRanks;
    }

    private int getRankUp(int yesterday, int today) {
        return yesterday - today;
    }

    private float getRankUpPercent(int diff, int base) {
        if (base == 0)
            return 0;
        else return diff / base;
    }

    private void setRank(List<BccRank> unPublishRanks, String rankType) {
        if (unPublishRanks.size() == 0)
            return;
        long start;
        start = System.currentTimeMillis();
        BccRank bccRank;
        for (int i = 0; i < unPublishRanks.size(); i++) {
            bccRank = unPublishRanks.get(i);
            setRank(bccRank, rankType, (i + 1));
            bccRankService.save(bccRank);
        }
        log.info("设置，consume:{}ms", (System.currentTimeMillis() - start));
    }

    private void setScoreRank(List<BccRank> unPublishRanks, String rankType) {
        long start;
        start = System.currentTimeMillis();
        BccRank bccRank;
        for (int i = 0; i < unPublishRanks.size(); i++) {
            bccRank = unPublishRanks.get(i);
            setRank(bccRank, rankType, (i + 1));
            setScore(bccRank, rankType.replace("rank_", "") + "_defeat", ((float) unPublishRanks.size() - i - 1) / (float) unPublishRanks.size());
            double a = 0.0;
            if ((i + 1) == unPublishRanks.size()) {
                a = Math.random();
            }
            double rate = MathUtil.div(i+1-a,unPublishRanks.size(),6);
            double score = MathUtil.sub(1,rate);
            setScore(bccRank,rankType.replace("rank_",""),(float) score);
            bccRankService.save(bccRank);
        }
        log.info("设置，consume:{}ms", (System.currentTimeMillis() - start));
    }

    /**
     * 整合所有信息，进行排名 BccBasicInfo  BccInfoEdit BccDailyInfo BccIndexInfo
     */
    private BccAllInfo getAllInfo(BccBasicInfo basicInfo) {
        String bccId = basicInfo.getBccId();
        List<BccInfoEdit> list = bccInfoEditService.findByBccIdAndFieldState(basicInfo.getBccId(), Bcc.RecordState.PUBLISH);
        List<BccDailyInfo> dailyInfos = bccDailyInfoService.findByBccIdAndRecordState(basicInfo.getBccId(), Bcc.RecordState.PUBLISH);
        BccDailyInfo bccDailyInfo = null;
        if (dailyInfos.size() == 1)
            bccDailyInfo = dailyInfos.get(0);
        List<BccIndexInfo> indexInfos = bccIndexInfoService.findByBccIdAndRecordState(basicInfo.getBccId(), Bcc.RecordState.PUBLISH);

        BccPriceInfo bccPriceInfo = null;
        BccBatch bccBatch = bccBatchService.findOneByBatchTypeAndBatchStateOrderByBatchTimeEndDesc(Bcc.BathType.CRAWL_PRICE_INFO, Bcc.BathState.HANDLE_DONE);
        if (bccBatch != null && StringUtils.isNotEmpty(bccBatch.getBatchNo())) {
            String batchNo = bccBatch.getBatchNo();
            List<BccPriceInfo> priceInfos = bccPriceInfoService.findByBccIdAndBatchNoAndRecordState(bccId, batchNo, Bcc.RecordState.PUBLISH);
            if (priceInfos.size() == 1) {
                bccPriceInfo = priceInfos.get(0);
            }
        }

        JSONObject other = new JSONObject();
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.add(Calendar.DAY_OF_MONTH, -30);
        List<BccPriceDay> priceDays = bccPriceDayService.findByBccIdAndCreateTimeGreaterThan(bccId, calendar.getTime());
        BccPriceDay priceDay;
        List<Double> volumeList = new ArrayList<>();
        for (BccPriceDay priceDay1 : priceDays) {
            priceDay = priceDay1;
            Double volume = getDouble(priceDay.getVolumeBtc());
            volumeList.add(volume);
        }
        other.put(Bcc.Item.volumeUsdAver30, MathUtil.mean(convert(volumeList)));
        return new BccAllInfo(basicInfo, bccDailyInfo, bccPriceInfo, list, indexInfos, other);
    }

    /**
     * 记录需要人工编辑的字段
     *
     * @param basicInfo
     * @param itemField
     */
    private void saveEditField(BccBasicInfo basicInfo, JSONObject itemField) {
        basicInfo.setEditField(itemField.toString());
        basicInfo.setUpdateTime(new Date());
        bccBasicInfoService.save(basicInfo);
    }

    private void save2RankHis(BccRank bccRankPublish) {
        BccRankHis bccRankHis = new BccRankHis();
        BeanUtils.copyProperties(bccRankPublish, bccRankHis);
        BccRankHisService.save(bccRankHis);
    }


    /**
     * 获取计算规则
     */
    private List<BccScoreRule> getBitCoinHandleRule(BccBasicInfo bccBasicInfo, String ruleClass) {
        String bccId = bccBasicInfo.getBccId();
        if (StringUtils.isEmpty(bccId))
            return null;
        List<BccScoreRule> defaultList = bccScoreRuleService.findByBccIdAndScoreClass(Bcc.BCC_DEDAULT, ruleClass);
        List<BccScoreRule> ruleList = new ArrayList<>();
        for (BccScoreRule defaultRule : defaultList) {
            List<BccScoreRule> list = bccScoreRuleService.findByBccIdAndScoreClass(bccId, defaultRule.getScoreClass());
            if (list.size() == 1) {
                ruleList.add(list.get(0));
            }
            else {
                ruleList.add(defaultRule);
            }
        }
        return ruleList;
    }


    /**
     * 获取综合评分(rank)
     */
    private void calculateAndSetRankScore(BccRank bccRank, BccScoreRule bccScoreRule) {
        String rule = bccScoreRule.getRule();
        rule = getRankCalculateRule(rule);
        if (StringUtils.isEmpty(rule))
            return;
        float score = 0;
        JSONObject ruleJ = JSONObject.fromObject(rule);
        for (Object o : ruleJ.entrySet()) {
            Map.Entry<String, String> entry = (Map.Entry<String, String>) o;
            String item = entry.getKey();
            String percent = entry.getValue();
            float value = getScore(bccRank, item);
            score += value * getFloat(percent);
        }
        setScore(bccRank, bccScoreRule.getScoreType(), score);

        String fieldDescription = bccScoreRule.getScoreType();
        if (StringUtils.isNotEmpty(fieldDescription)) {
            calculateAndSetRankDescription(bccScoreRule, bccRank);
        }
    }

    private float calculateBasicScore3(Map<String, Double> normal, BccAllInfo bccAllInfo, BccScoreRule bccScoreRule, JSONObject itemField) {
        String scoreType = bccScoreRule.getScoreType();
        String rule = bccScoreRule.getRule();
        float score = 0;
        if (StringUtils.isEmpty(rule))
            return getDefaultScore();
        JSONObject ruleJ = JSONObject.fromObject(rule);
        JSONObject allInfo = bccAllInfo.getJsonObject();
        String bccId = bccScoreRule.getBccId();
        switch (scoreType) {
            case Bcc.Score.BasicScore.supply_score: {//代币供给指数
                String key = Bcc.Item.totalSupply;
                score += calculateItemScore3(normal.get(getMeanName(key)), normal.get(getStandardDeviationName(key)), allInfo.optString(key), ruleJ.optString(key), itemField, key);
                key = Bcc.Item.availableSupply;
                score += calculateItemScore3(normal.get(getMeanName(key)), normal.get(getStandardDeviationName(key)), allInfo.optString(key), ruleJ.optString(key), itemField, key);
                key = Bcc.Item.blockCreateTimeGap;
                score += calculateItemScore3(normal.get(getMeanName(key)), normal.get(getStandardDeviationName(key)), allInfo.optString(key), ruleJ.optString(key), itemField, key);
                score = (float) transport(score);
                break;
            }
            case Bcc.Score.BasicScore.need_score: {//代币需求指数
                String key = Bcc.Item.whole_average_daily_30d;
                score += calculateItemScore3(normal.get(getMeanName(key)), normal.get(getStandardDeviationName(key)), allInfo.optString(key), ruleJ.optString(key), itemField, key);
                key = Bcc.Item.volumeUsdAver30;
                score += calculateItemScore3(normal.get(getMeanName(key)), normal.get(getStandardDeviationName(key)), allInfo.optString(key), ruleJ.optString(key), itemField, key);
                key = Bcc.Item.dailyVisitRank;
                score += calculateItemScore3(normal.get(getMeanName(key)), normal.get(getStandardDeviationName(key)), allInfo.optString(key), ruleJ.optString(key), itemField, key);
                break;
            }
            case Bcc.Score.BasicScore.inner_score: {//代币属性指数
                String key = Bcc.Item.icoToNowDay;
                score += calculateItemScore3(normal.get(getMeanName(key)), normal.get(getStandardDeviationName(key)), allInfo.optString(key), ruleJ.optString(key), itemField, key);
                key = Bcc.Item.onlineToNowDay;
                score += calculateItemScore3(normal.get(getMeanName(key)), normal.get(getStandardDeviationName(key)), allInfo.optString(key), ruleJ.optString(key), itemField, key);
                key = Bcc.Item.officialSiteUrlCount;
                score += calculateItemScore3(normal.get(getMeanName(key)), normal.get(getStandardDeviationName(key)), allInfo.optString(key), ruleJ.optString(key), itemField, key);
                key = Bcc.Item.marketCount;
                score += calculateItemScore3(normal.get(getMeanName(key)), normal.get(getStandardDeviationName(key)), allInfo.optString(key), ruleJ.optString(key), itemField, key);
                break;
            }
            case Bcc.Score.BasicScore.mood_score: {//情感指数
                List<BccDailyInfoHis> dailyInfoHisList = bccDailyInfoHisService.findByBccIdYesterday(bccId);
                BccDailyInfoHis yesterday = null;
                if (dailyInfoHisList.size() > 0)
                    yesterday = dailyInfoHisList.get(0);
                else
                    break;
                String key = Bcc.Item.dailyVisitRank;
                score += calculateItemScore3(normal.get(getMeanName(key)), normal.get(getStandardDeviationName(key)), getChangeRate(getDouble(allInfo.optString(key)), getDouble(yesterday.getDailyVisitRank())), ruleJ.optString(key), itemField, key);
                key = Bcc.Item.searchIndex;
                score += calculateItemScore3(normal.get(getMeanName(key)), normal.get(getStandardDeviationName(key)), getChangeRate(getDouble(allInfo.optString(key)), getDouble(yesterday.getSnsCommentCount())), ruleJ.optString(key), itemField, key);
                key = Bcc.Item.snsCommentCount;
                score += calculateItemScore3(normal.get(getMeanName(key)), normal.get(getStandardDeviationName(key)), getChangeRate(getDouble(allInfo.optString(key)), getDouble(ruleJ.optString(key))), ruleJ.optString(key), itemField, key);
                break;
            }
            case Bcc.Score.BasicScore.safe_score: {//安全指数
                String key = Bcc.Item.top3Ratio;
                score += calculateItemScore3(normal.get(getMeanName(key)), normal.get(getStandardDeviationName(key)), allInfo.optString(key), ruleJ.optString(key), itemField, key);
                key = Bcc.Item.githubStarCount;
                score += calculateItemScore3(normal.get(getMeanName(key)), normal.get(getStandardDeviationName(key)), allInfo.optString(key), ruleJ.optString(key), itemField, key);
                break;
            }
            case Bcc.Score.BasicScore.future_score: {
                break;
            }
        }
        return score;
    }

    @Deprecated
    public float calculateBasicScore2(BccAllInfo bccAllInfo, BccAllInfo btcInfo, BccScoreRule bccScoreRule, JSONObject itemField, JSONObject btcField) {
        String bccId = bccAllInfo.getBccBasicInfo().getBccId();
        String btcId = btcInfo.getBccBasicInfo().getBccId();
        String scoreType = bccScoreRule.getScoreType();
        JSONObject allInfo = bccAllInfo.getJsonObject();
        JSONObject btcAllInfo = btcInfo.getJsonObject();
        String rule = bccScoreRule.getRule();
        if (StringUtils.isEmpty(rule))
            return getDefaultScore();

        float score = 0;
        JSONObject ruleJ = JSONObject.fromObject(rule);
        switch (scoreType) {
            case Bcc.Score.BasicScore.supply_score: {//代币供给系数
                String key = "totalSupply";
                score += calculateItemScore2(allInfo.opt(key), btcAllInfo.opt(key), ruleJ.optString(key), itemField, btcField, key);
                key = "availableSupply";
                score += calculateItemScore2(allInfo.opt(key), btcAllInfo.opt(key), ruleJ.optString(key), itemField, btcField, key);
                key = "blockCreateTimeGap";
                score += calculateItemScore2(allInfo.opt(key), btcAllInfo.opt(key), ruleJ.optString(key), itemField, btcField, key);
                key = "computeAbility";
                score += calculateItemScore2(allInfo.opt(key), btcAllInfo.opt(key), ruleJ.optString(key), itemField, btcField, key);
                break;
            }
            case Bcc.Score.BasicScore.need_score: {//代币需求系数 日
                String key = "whole_average_daily_30d";
                score += calculateItemScore(btcAllInfo.opt(key), allInfo.opt(key), ruleJ.optString(key), itemField, btcField, toCamel(key));
                key = "volumeUsd";
                score += calculateItemScore(btcAllInfo.opt(toCamel(key)), allInfo.opt(toCamel(key)), ruleJ.optString(key), itemField, btcField, toCamel(key));
                key = "dailyVisitRank";
                score += calculateItemScore(btcAllInfo.opt(key), allInfo.opt(key), ruleJ.optString(key), itemField, btcField, toCamel(key));
                break;
            }
            case Bcc.Score.BasicScore.inner_score: {//代币属性系数
                String key = "onlineToNowDay";
                score += calculateItemScore(btcAllInfo.opt("onlineToNowDay"), allInfo.opt("onlineToNowDay"), ruleJ.optString(key), itemField, btcField, key);
                key = "icoToNowDay";
                score += calculateItemScore(btcAllInfo.opt("onlineToNowDay"), allInfo.opt("onlineToNowDay"), ruleJ.optString(key), itemField, btcField, key);
                key = "marketCount";
                score += calculateItemScore(btcAllInfo.opt("onlineToNowDay"), allInfo.opt("onlineToNowDay"), ruleJ.optString(key), itemField, btcField, key);
                key = "officialSiteUrlCount";
                score += calculateItemScore(btcAllInfo.opt("onlineToNowDay"), allInfo.opt("onlineToNowDay"), ruleJ.optString(key), itemField, btcField, key);
                break;
            }
            case Bcc.Score.BasicScore.mood_score: {//用户情绪指数 日
                String key = "dailyVisitRank";
                String visitRank = allInfo.optString(key);
                String visitRankYesterday = null;
                List<BccDailyInfoHis> list = bccDailyInfoHisService.findByBccIdYesterday(bccId);
                if (list.size() > 0) {
                    visitRankYesterday = list.get(0).getDailyVisitRank();
                }
                float change = calculateChange(visitRank, visitRankYesterday);

                String visitRankBtc = btcAllInfo.optString(key);
                List<BccDailyInfoHis> listBtc = bccDailyInfoHisService.findByBccIdYesterday(btcId);
                String visitRankBtcYesterday = null;
                if (listBtc.size() > 0) {
                    visitRankBtcYesterday = listBtc.get(0).getDailyVisitRank();
                }
                float changeBtc = calculateChange(visitRankBtc, visitRankBtcYesterday);
                score += calculateItemScore(changeBtc, change, ruleJ.optString(key), itemField, btcField, key);

                key = "snsCommentCount";
                String comment = allInfo.optString(key);

                //TODO 这块逻辑要理一理 commentYesterday visitRankYesterday
                String commentYesterday = null;
                if (list.size() > 0) {
                    visitRankYesterday = list.get(0).getSnsCommentCount();
                }
                change = calculateChange(comment, commentYesterday);

                String commentBtc = btcAllInfo.optString(key);
                String commentBtcYesterday = null;
                if (listBtc.size() > 0) {
                    commentBtcYesterday = listBtc.get(0).getSnsCommentCount();
                }
                changeBtc = calculateChange(commentBtc, commentBtcYesterday);
                score += calculateItemScore(changeBtc, change, ruleJ.optString(key), itemField, btcField, key);

                key = "whole_average_daily_30d";
                String daily30 = allInfo.optString(key);
                String daily30Yesterday = null;
                List<BccIndexInfo> indexList = bccIndexInfoService.findByBccIdAndIndexTitleYesterday(bccId, key);
                if (indexList.size() > 0) {
                    daily30Yesterday = indexList.get(0).getIndexValue();
                }
                change = calculateChange(daily30, daily30Yesterday);

                String daily30Btc = btcAllInfo.optString(key);
                String daily30YesterdayBtc = null;
                List<BccIndexInfo> indexBtcList = bccIndexInfoService.findByBccIdAndIndexTitleYesterday(bccId, key);
                if (indexBtcList.size() > 0) {
                    daily30YesterdayBtc = indexBtcList.get(0).getIndexValue();
                }
                changeBtc = calculateChange(daily30Btc, daily30YesterdayBtc);
                score += calculateItemScore(changeBtc, change, ruleJ.optString(key), itemField, btcField, toCamel(key));

                break;
            }
            case Bcc.Score.BasicScore.safe_score: {//安全指数
                String key = "dailyVisitRank";
                score += calculateItemScore(btcAllInfo.opt(key), allInfo.optString(key), ruleJ.optString(key), itemField, btcField, key);
                key = "top3Ratio";
                score += calculateItemScore(btcAllInfo.opt(key), allInfo.optString(key), ruleJ.optString(key), itemField, btcField, key);
                break;
            }
            case Bcc.Score.BasicScore.future_score://未来指数
                break;
        }

        return score;
    }

    @Deprecated
    public float calculateBasicScore(BccAllInfo bccAllInfo, BccAllInfo btcInfo, BccScoreRule bccScoreRule, JSONObject itemField, JSONObject btcField) {
        String rule = bccScoreRule.getRule();
        if (StringUtils.isEmpty(rule))
            return getDefaultScore();

        float score = 0;
        JSONObject ruleJ = JSONObject.fromObject(rule);
        Iterator iterator = ruleJ.entrySet().iterator();
        JSONObject allInfo = bccAllInfo.getJsonObject();
        JSONObject btcAllInfo = btcInfo.getJsonObject();
        while (iterator.hasNext()) {
            Map.Entry<String, String> entry = (Map.Entry<String, String>) iterator.next();
            String item = entry.getKey();
            if (StringUtils.isEmpty(item))
                continue;
            item = toCamel(item);
            String percent = entry.getValue();
            Object value = allInfo.opt(item);
            Object btcValue = btcAllInfo.opt(item);
            try {
                score += calculateItemScore(btcValue, value, percent, itemField, btcField, item);
            } catch (Exception e) {
                itemField.put(item, "");
            }
        }
        log.info("bccId:{},type:{},rule:{},score:{}", bccAllInfo.getBccBasicInfo().getBccId(), bccScoreRule.getScoreType(), rule, score);
        return score;
    }


    /**
     * 设定评分
     *
     * @param bccRank
     * @param type
     * @param score
     */
    private void setScore(BccRank bccRank, String type, float score) {
        type = toCamel(type);
        setField(bccRank, type, score);
    }

    private void setRanKDescription(BccRank bccRank, String type, String description) {
        type = toCamel(type);
        setField(bccRank, type, description);
    }

    private void setRank(BccRank bccRank, String type, int rank) {
        type = toCamel(type);
        setField(bccRank, type, rank);
    }

    /**
     * 获取评分
     */
    private float getScore(BccRank bccRank, String scoreType) {
        try {
            scoreType = toCamel(scoreType);
            Field f = bccRank.getClass().getDeclaredField(scoreType);
            Object o = getField(bccRank, scoreType);
            if (null == o) {
                return getDefaultScore();
            } else {
                return getFloat(o);
            }
        } catch (NoSuchFieldException e) {
            log.info("", e);
        }
        return getDefaultScore();
    }

    private float getFloat(Object o) {
        try {
            if (o == null)
                return getDefaultScore();
            if (o instanceof Float) {
                return (Float) o;
            } else if (o instanceof Integer) {
                return (int) o;
            } else if (o instanceof String) {
                if (StringUtils.isEmpty((String) o))
                    return getDefaultScore();
                return Float.parseFloat((String) o);
            }
        } catch (Exception e) {
            log.info("", e);
        }

        return getDefaultScore();
    }

    private double getDouble(Object o) {
        try {
            if (o == null) {
                return getDefaultScore();
            } else if (o instanceof Double) {
                return (Double) o;
            } else if (o instanceof Float) {
                return (Double) o;
            } else if (o instanceof Integer) {
                return (Integer) o;
            } else if (o instanceof String) {
                if (StringUtils.isEmpty((String) o))
                    return getDefaultScore();
                return Double.parseDouble((String) o);
            }
        } catch (Exception e) {
            log.info("", e);
        }

        return getDefaultScore();
    }


    /**
     * 转驼峰格式
     */
    private static String toCamel(String param, char separator) {
        if (StringUtils.isEmpty(param)) {
            return "";
        }

        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (c == separator) {
                if (++i < len) {
                    sb.append(Character.toUpperCase(param.charAt(i)));
                }
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    private static String toCamel(String param) {
        return toCamel(param, Bcc.SEPARATOR);
    }


    private void calculateAndSetRankDescription(BccScoreRule bccScoreRule, BccRank bccRank) {
        String scoreType = bccScoreRule.getScoreType();
        scoreType = toCamel(scoreType);
        Object o = getField(bccRank, scoreType);
        if (null == o) {
            return;
        }
        float rankScore = (float) o;
        String rule = bccScoreRule.getRule();
        if (StringUtils.isEmpty(rule))
            return;
        String[] rules = rule.split("%");
        String range = rules[1];
        String grade = rules[2];
        JSONArray rangeList = JSONArray.fromObject(range);
        JSONArray gradeList = JSONArray.fromObject(grade);
        int gradeIndex = -1;
        int rangeNum = rangeList.size() - 1;
        for (int i = 0; i < rangeNum; i++) {
            if (rankScore < rangeList.getDouble(i)) {
                break;
            }
            gradeIndex++;
        }
        if (gradeIndex < 0)
            gradeIndex = 0;
        if (gradeIndex >= rangeNum) {
            gradeIndex = rangeNum - 1;
        }
        String rankDesc = gradeList.getString(gradeIndex);

        String type = bccScoreRule.getScoreType().split(String.valueOf(Bcc.SEPARATOR))[0];
        String desc = type + Bcc.SEPARATOR + "description";

        setRanKDescription(bccRank, desc, rankDesc);
        if (StringUtils.equals(type, "value")) {
            bccRank.setValueStage(gradeIndex + 1);
        }
    }

    private float calculateItemScore(Object base, Object value, String percent, JSONObject itemField, JSONObject btcField, String item) {
        boolean isNull = false;
        if (null == base) {
            btcField.put(item, "");
            isNull = true;
        }
        if (base instanceof String) {
            if (StringUtils.isEmpty((String) base)) {
                btcField.put(item, "");
                isNull = true;
            }
        }
        if (value == null) {
            itemField.put(item, "");
            isNull = true;
        }
        if (value instanceof String) {
            if (StringUtils.isEmpty((String) value)) {
                itemField.put(item, "");
                isNull = true;
            }
        }
        if (isNull) {
            return getDefaultScore();
        }
        float item1 = getFloat(value);
        float percent1 = getFloat(percent);
        float base1 = getFloat(base);
        if (base1 == 0 || item1 == 0 || percent1 == 0)
            return 0;
        return (item1 * percent1) / base1;
    }

    private float calculateItemScore2(Object base, Object value, String percent, JSONObject itemField, JSONObject btcField, String item) {
        boolean isNull = false;
        if (null == base) {
            itemField.put(item, "");
            isNull = true;
        }
        if (base instanceof String) {
            if (StringUtils.isEmpty((String) base)) {
                itemField.put(item, "");
                isNull = true;
            }
        }
        if (value == null) {
            btcField.put(item, "");
            isNull = true;
        }
        if (value instanceof String) {
            if (StringUtils.isEmpty((String) value)) {
                btcField.put(item, "");
                isNull = true;
            }
        }
        if (isNull) {
            return getDefaultScore();
        }
        float item1 = getFloat(value);
        float percent1 = getFloat(percent);
        float base1 = getFloat(base);
        if (base1 == 0 || item1 == 0 || percent1 == 0)
            return 0;
        return (item1 * percent1) / base1;
    }

    private double calculateItemScore3(Double mean, Double standard, Object value, String percent, JSONObject itemField, String item) {
        if (mean == null || standard == null) {
            log.info("mean或者standard为空,mean={},standard={}", mean, standard);
            return 0;
        }
        double f = getDouble(value);
        if (f == 0d) {
            itemField.put(item, value);
            Random random = new Random(10);
            f = mean * (0.55 + random.nextInt() * 0.1);
        }
        if (standard == 0) {
            return 0d;
        }
        double diff = f - mean;
        if (diff == 0)
            return 0;
        double score = (diff / (6 * Math.pow(standard, 2))) + 0.5;
        log.info("item:{},value:{},mean:{},standard:{} score:{}", item, value, mean, standard, score);
        if (score < 0)
            score = 0;
        if (score > 1)
            score = 1;
        return score * getDouble(percent);
    }

    private double transport(double d) {
        if (d == 0)
            return 0;
        else
            return 1 - d;
    }

    private float calculateChange(String today, String yesterday) {
        if (StringUtils.isEmpty(today) || StringUtils.isEmpty(yesterday)) {
            return getDefaultScore();
        }
        float todayf = getFloat(today);
        float yesterdayf = getFloat(yesterday);
        if (todayf == 0 || yesterdayf == 0)
            return 0;
        return (todayf - yesterdayf) / yesterdayf;
    }


    private String getRankCalculateRule(String rule) {
        if (StringUtils.isEmpty(rule))
            return null;
        String[] strings = rule.split("%");
        return strings[0];
    }


    /**
     * 创建初始评分记录
     */
    private BccRank getInitBccRank(String unPublishRankBatch, String bccId) {
        BccRank bccRank;
        bccRank = new BccRank();
        bccRank.setBccId(bccId);
        bccRank.setValueStage(0);
        bccRank.setSupplyScore(getDefaultScore());
        bccRank.setNeedScore(getDefaultScore());
        bccRank.setNeedScoreYesterday(getDefaultScore());
        bccRank.setNeedScoreChange(getDefaultScore());
        bccRank.setInnerScore(getDefaultScore());
        bccRank.setInnerScoreYesterday(getDefaultScore());
        bccRank.setInnerScoreChange(getDefaultScore());
        bccRank.setMoodScore(getDefaultScore());
        bccRank.setMoodScoreYesterday(getDefaultScore());
        bccRank.setMoodScoreChange(getDefaultScore());
        bccRank.setSafeScore(getDefaultScore());
        bccRank.setSafeScoreYesterday(getDefaultScore());
        bccRank.setSafeScoreChange(getDefaultScore());
        bccRank.setFutureScore(getDefaultScore());
        bccRank.setFutureScoreYesterday(getDefaultScore());
        bccRank.setFutureScoreChange(getDefaultScore());
        //
        bccRank.setValueScore(getDefaultScore());
        bccRank.setValueScoreYesterday(getDefaultScore());
        bccRank.setValueScoreChange(getDefaultScore());
        bccRank.setValueScoreYesterday(getDefaultScore());
        bccRank.setValueScoreChange(getDefaultScore());
        bccRank.setPotentialScore(getDefaultScore());
        bccRank.setGasScore(getDefaultScore());

        bccRank.setValuePriceBtc(0);
        bccRank.setValuePriceCny(0);
        bccRank.setValuePriceUsd(0);

        //
        bccRank.setRankValueToday(getDefaultRank());
        bccRank.setRankValueYesterday(getDefaultRank());
        bccRank.setRankPotentialToday(getDefaultRank());
        bccRank.setRankPotentialYesterday(getDefaultRank());
        bccRank.setRankGasToday(getDefaultRank());
        bccRank.setRankGasYesterday(getDefaultRank());

        bccRank.setRankPotentialUp(0);
        bccRank.setPotentialUp(0);
        bccRank.setPotentialUpPercent(0);
        bccRank.setRankValueUp(0);
        bccRank.setValueUp(0);
        bccRank.setValueUpPercent(0);

        bccRank.setSupplyScoreDefeat(0);
        bccRank.setNeedScoreDefeat(0);
        bccRank.setInnerScoreDefeat(0);
        bccRank.setMoodScoreDefeat(0);
        bccRank.setSafeScoreDefeat(0);
        bccRank.setFutureScoreDefeat(0);

        bccRank.setBatchNo(unPublishRankBatch);
        bccRank.setRecordState(Bcc.RecordState.UN_PUBLISH);
        bccRank.setCreateTime(new Date());
        bccRank.setUpdateTime(new Date());
        return bccRank;
    }

    public void cache2Redis() {
        String nextVersion = bccRedisService.getNextVersion(Bcc.Cache.Version.CALCULATE);
        log.info("nextVersion:{}", nextVersion);
        cacheRank(nextVersion);
        cacheDetail(nextVersion);
        cacheRankUp(nextVersion);
        bccRedisService.updateVersion(Bcc.Cache.Version.CALCULATE, nextVersion);
        log.info("switch to version:{}", bccRedisService.getCurrentVersion(Bcc.Cache.Version.CALCULATE));
    }

    private void cacheRankUp(String version) {
        int limit = 5;
        String rankType = Bcc.RankType.RANK_VALUE_UP;
        //查询第一页
        Sort sort = new Sort(Sort.Direction.ASC, rankType);
        Pageable pageable = PageRequest.of(0, limit, sort);
        Page<BccRank> page = bccRankService.findByRecordState(Bcc.RecordState.PUBLISH, pageable);
        BccShowControl bccShowControl = bccShowControlService.findByBccIdAndShowType(Bcc.BCC_DEDAULT, Bcc.ShowType.Top);
        JSONObject jsonObject = new JSONObject();
        if (page != null) {
            List<BccRank> bccRanks = page.getContent();
            jsonObject.put("valueTop", getTopShow(bccRanks, bccShowControl).toString());
        }
        rankType = Bcc.RankType.RANK_POTENTIAL_UP;
        sort = new Sort(Sort.Direction.ASC, rankType);
        pageable = PageRequest.of(0, limit, sort);
        page = bccRankService.findByRecordState(Bcc.RecordState.PUBLISH, pageable);
        if (page != null) {
            List<BccRank> bccRanks = page.getContent();
            jsonObject.put("potentialTop", getTopShow(bccRanks, bccShowControl).toString());
        }
        bccRedisService.cacheTop2Redis(version, jsonObject);

    }

    private void cacheRank(String version) {
        String[] scores = new String[]{Bcc.RankType.RANK_VALUE_TODAY, Bcc.RankType.RANK_GAS_TODAY, Bcc.RankType.RANK_POTENTIAL_TODAY};

        for (String score : scores) {
            log.info("cache:{}", score);
            Sort sort = new Sort(Sort.Direction.ASC, score);
            Pageable pageable = PageRequest.of(0, pageSizeHome, sort);
            Page<BccRank> page = bccRankService.findByRecordState(Bcc.RecordState.PUBLISH, pageable);
            if (page == null) {
                log.info("没有内容可跟新到redis");
                return;
            }
            List<BccRank> bccRanks = page.getContent();
            if (bccRanks.size() == 0) {
                log.info("还没有主页数据，现在去计算，可能会有点慢哦");
                execute();
            }

            int pages = page.getTotalPages();
            bccRedisService.cacheBccCount2Redis(score, version, page.getTotalElements());
            BccShowControl bccShowControl = bccShowControlService.findByBccIdAndShowType(Bcc.BCC_DEDAULT, score);
            for (int j = 0; j < pages; j++) {
                log.info("第{}页", j);
                if (j != 0) {
                    pageable = PageRequest.of(j, pageSizeHome, sort);
                    page = bccRankService.findByRecordState(Bcc.RecordState.PUBLISH, pageable);
                }
                bccRanks = page.getContent();
                if (bccRanks != null) {
                    BccRank bccRank;
                    JSONArray show = new JSONArray();
                    for (BccRank bccRank1 : bccRanks) {
                        bccRank = bccRank1;
                        JSONObject allInfo = getHomePageInfo(bccRank);
                        JSONObject Item = getShowInfo(allInfo, bccShowControl);
                        bccRedisService.cacheRank2Redis(score, bccRank.getBccId(), version, Item);
                        show.add(Item);
                    }
                    bccRedisService.cacheRankPage(score, pageSizeHome, j + 1, version, show);
                }
            }
        }
    }

    private void cacheDetail(String version) {
        Sort sort = new Sort(Sort.Direction.ASC, Bcc.RankType.RANK_VALUE_TODAY);
        Pageable pageable = PageRequest.of(0, pageSizeHome, sort);
        Page<BccRank> page = bccRankService.findByRecordState(Bcc.RecordState.PUBLISH, pageable);
        if (page == null) {
            log.info("没有内容可跟新到redis");
            return;
        }
        List<BccRank> bccRanks = page.getContent();
        if (bccRanks.size() == 0) {
            log.info("还没有主页数据，现在去计算，可能会有点慢哦");
            execute();
        }

        int pages = page.getTotalPages();
        for (int j = 0; j < pages; j++) {
            log.info("第{}页", j);
            if (j != 0) {
                pageable = PageRequest.of(j, pageSizeHome, sort);
                page = bccRankService.findByRecordState(Bcc.RecordState.PUBLISH, pageable);
            }
            bccRanks = page.getContent();
            if (bccRanks != null) {
                BccRank bccRank;
                BccShowControl detailControl = bccShowControlService.findByBccIdAndShowType(Bcc.BCC_DEDAULT, Bcc.RankType.RANK_VALUE_TODAY_DETAIL);
                for (BccRank bccRank1 : bccRanks) {
                    bccRank = bccRank1;
                    JSONObject allInfo = getHomePageInfo(bccRank);
                    JSONObject detail = getShowInfo(allInfo, detailControl);
                    bccRedisService.cacheDetail2Redis(bccRank.getBccId(), version, detail);
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        log.info("", e);
                    }
                }
            }
        }
    }


    private JSONArray getTopShow(List<BccRank> bccRanks, BccShowControl bccShowControl) {
        JSONArray jsonArray = new JSONArray();
        for (BccRank bccRank : bccRanks) {
            JSONObject item = getTopAll(bccRank);
            JSONObject show = getShowInfo(item, bccShowControl);
            jsonArray.add(show);
        }
        return jsonArray;
    }

    private JSONObject getTopAll(BccRank bccRank) {
        JSONObject info = new JSONObject();
        String bccId = bccRank.getBccId();
        //rank
        info.putAll(BeanSerial.Bean2Json(bccRank));
        List<BccBasicInfo> list = bccBasicInfoService.findByBccIdAndRecordState(bccId, Bcc.RecordState.PUBLISH);
        //basic
        if (list.size() == 1) {
            info.putAll(BeanSerial.Bean2Json(list.get(0)));
        }
        return info;
    }

    private JSONObject getHomePageInfo(BccRank bccRank) {
        JSONObject info = new JSONObject();
        String bccId = bccRank.getBccId();
        //rank
        info.putAll(BeanSerial.Bean2Json(bccRank));
        List<BccBasicInfo> list = bccBasicInfoService.findByBccIdAndRecordState(bccId, Bcc.RecordState.PUBLISH);
        //basic
        if (list.size() == 1) {
            info.putAll(BeanSerial.Bean2Json(list.get(0)));
        }

        //daily
        List<BccDailyInfo> list1 = bccDailyInfoService.findByBccIdAndRecordState(bccId, Bcc.RecordState.PUBLISH);
        if (list1.size() == 1) {
            info.putAll(BeanSerial.Bean2Json(list1.get(0)));
        }
        //edit
        List<BccInfoEdit> edits = bccInfoEditService.findByBccIdAndFieldType(Bcc.BCC_DEDAULT, Bcc.FieldType.HomePage);
        BccInfoEdit bccInfoEdit;
        for (BccInfoEdit edit : edits) {
            bccInfoEdit = edit;
            info.put(bccInfoEdit.getFieldKey(), bccInfoEdit.getFieldValue());
        }
        edits = bccInfoEditService.findByBccIdAndFieldType(bccId, Bcc.FieldType.HomePage);
        for (BccInfoEdit edit : edits) {
            bccInfoEdit = edit;
            info.put(bccInfoEdit.getFieldKey(), bccInfoEdit.getFieldValue());
        }

        List<BccPriceInfo> prices = bccPriceInfoService.findOneByBccIdAndRecordStateOrderByCreateTimeDesc(bccId, Bcc.RecordState.PUBLISH);
        if (prices.size() > 0) {
            info.putAll(BeanSerial.Bean2Json(prices.get(0)));
        }
        JSONObject fakeData = new JSONObject();
        info.putAll(fakeData);
        return info;
    }
}
